package com.sms.server;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sms.client.EmailService;

public class EmailServiceImpl extends RemoteServiceServlet implements EmailService {

	private static final String mailServer = "smtp.gmail.com";

	public void sendMail(String mailServer, String[] toAddresses, String subject, String messageBody, Map attachments, String[] ccAddresses, String[] bccAddresses, String[] replyTo, String fromAddressdisplayName) {
		try {

			Properties props = System.getProperties();
			props.put("mail.transport.protocol", "smtp");
			props.put("mail.smtp.auth", "true");
			props.put("mail.mail.smtp.ssl.enable", "true");
			props.put("mail.smtp.host", mailServer);
			props.put("mail.smtps.host", mailServer);
			props.put("mail.smtp.starttls.enable", "true");
			java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
			String from = null;
			from = "test@cogentmail.com";

			// Get a mail session

			Authenticator auth = new SMTPAuthenticator();
			Session session = Session.getInstance(props, auth);

			// Define a new mail message
			Message message = new MimeMessage(session);
			Map<String, HashSet<String>> recipientsMap = getRecipientsEmailMap(toAddresses, ccAddresses, bccAddresses);
			HashSet<String> toAddressSet = (HashSet<String>) recipientsMap.get("toAddress");
			HashSet<String> ccAddressSet = (HashSet<String>) recipientsMap.get("ccAddress");
			HashSet<String> bccAddressSet = (HashSet<String>) recipientsMap.get("bccAddress");
			//
			boolean processMailSending = false;
			int toLength = toAddressSet == null ? 0 : toAddressSet.size();
			if (toLength > 0) {

				InternetAddress[] toInternetAddresses = new InternetAddress[toAddressSet.size()];
				Iterator<String> toAddressIt = toAddressSet.iterator();
				int toIndex = 0;
				while (toAddressIt.hasNext()) {
					toInternetAddresses[toIndex] = new InternetAddress((String) toAddressIt.next());
					toIndex++;
				}

				InternetAddress fromEmailAddress = new InternetAddress(from);

				if (fromAddressdisplayName != null) {
					try {
						fromEmailAddress.setPersonal(fromAddressdisplayName);
					} catch (UnsupportedEncodingException e) {
						System.out.println(e.getLocalizedMessage());
					}
				}

				message.setFrom(fromEmailAddress);
				if (toAddressSet.size() > 0) {
					System.err.println("TO ADDRESS LIST " + toAddresses.toString());
					processMailSending = true;
					message.addRecipients(Message.RecipientType.TO, toInternetAddresses);
				}
			}

			// //Cc Address
			int ccAddressesLength = ccAddresses == null ? 0 : ccAddressSet.size();
			if (ccAddressesLength > 0) {
				InternetAddress[] ccInternetAddresses = new InternetAddress[ccAddressSet.size()];
				Iterator<String> ccAddressIt = ccAddressSet.iterator();
				int ccIndex = 0;
				while (ccAddressIt.hasNext()) {
					ccInternetAddresses[ccIndex] = new InternetAddress((String) ccAddressIt.next());
					ccIndex++;
				}
				if (ccAddressSet.size() > 0) {
					processMailSending = true;
					message.addRecipients(Message.RecipientType.CC, ccInternetAddresses);
				}
			}
			// Bcc Addresses
			int bccAddressesLength = bccAddresses == null ? 0 : bccAddressSet.size();

			if (bccAddressesLength > 0) {
				InternetAddress[] bccInternetAddresses = new InternetAddress[bccAddressSet.size()];
				Iterator<String> bccAddressIt = bccAddressSet.iterator();
				int bccIndex = 0;
				while (bccAddressIt.hasNext()) {
					bccInternetAddresses[bccIndex] = new InternetAddress((String) bccAddressIt.next());
					bccIndex++;
				}

				if (bccAddressSet.size() > 0) {
					processMailSending = true;
					message.addRecipients(Message.RecipientType.BCC, bccInternetAddresses);
				}
			}

			// Reply To Addresses

			int replyToLength = replyTo == null ? 0 : replyTo.length;
			if (replyToLength > 0) {
				List<String> replyToAddressesList = null;
				for (int i = 0; i < replyToLength; i++) {
					String replyToAddress = replyTo[i];
					if (replyToAddress != null && replyToAddress.trim().length() > 0) {
						if (replyToAddressesList == null) {
							replyToAddressesList = new ArrayList<String>();
						}
						replyToAddressesList.add(replyToAddress);
					}
				}

				int rplyToAddressListSize = replyToAddressesList == null ? 0 : replyToAddressesList.size();
				InternetAddress[] internetAddresses = new InternetAddress[rplyToAddressListSize];

				for (int i = 0; i < rplyToAddressListSize; i++) {
					String replyToAddress = (String) replyToAddressesList.get(i);
					InternetAddress emailAddress = new InternetAddress(replyToAddress);
					internetAddresses[i] = emailAddress;
				}
				message.setFrom(new InternetAddress(from));
				if (rplyToAddressListSize > 0) {
					processMailSending = true;
					message.setReplyTo(internetAddresses);
				}
			}

			if (processMailSending) {
				message.setSubject(subject);
				message.setSentDate(new Date());
				BodyPart messageBodyPart = new MimeBodyPart();
				messageBodyPart.setContent(messageBody, "text/html");
				Multipart multipart = new MimeMultipart();
				multipart.addBodyPart(messageBodyPart);
				// addAtachments(attachments, multipart);
				message.setContent(multipart);
				System.out.println("Mail sending........");
				Transport.send(message);
				System.out.println("Mail sent");
			}
		} catch (AddressException exception) {
			exception.printStackTrace();
		} catch (MessagingException exception) {
			exception.printStackTrace();
		} catch (Exception exception) {
			exception.printStackTrace();
		} catch (Throwable exception) {
			exception.printStackTrace();
		}
	}

	private static Map<String, HashSet<String>> getRecipientsEmailMap(String[] toAddress, String[] ccAddress, String[] bccAddress) {
		Map<String, HashSet<String>> addressMap = new HashMap<String, HashSet<String>>();

		addressMap.put("toAddress", new HashSet<String>());
		addressMap.put("ccAddress", new HashSet<String>());
		addressMap.put("bccAddress", new HashSet<String>());
		for (int toIndex = 0; toIndex < toAddress.length; toIndex++) {
			HashSet<String> toHashSet = (HashSet<String>) addressMap.get("toAddress");
			toHashSet.add(toAddress[toIndex]);
		}
		if (ccAddress != null) {
			HashSet<String> toHashSet = (HashSet<String>) addressMap.get("toAddress");
			HashSet<String> ccHashSet = (HashSet<String>) addressMap.get("ccAddress");
			for (int ccIndex = 0; ccIndex < ccAddress.length; ccIndex++) {
				if (!isEmailExist(toHashSet, ccAddress[ccIndex].trim())) {
					ccHashSet.add(ccAddress[ccIndex].trim());
				}
			}
		}

		if (bccAddress != null) {
			HashSet<String> toHashSet = (HashSet<String>) addressMap.get("toAddress");
			HashSet<String> ccHashSet = (HashSet<String>) addressMap.get("ccAddress");
			HashSet<String> bccHashSet = (HashSet<String>) addressMap.get("bccAddress");

			for (int bccIndex = 0; bccIndex < bccAddress.length; bccIndex++) {
				if (!isEmailExist(toHashSet, bccAddress[bccIndex].trim()) && !isEmailExist(ccHashSet, bccAddress[bccIndex].trim())) {
					bccHashSet.add(bccAddress[bccIndex].trim());
				}
			}
		}

		return addressMap;
	}

	private static boolean isEmailExist(HashSet<String> hashSet, String emailId) {
		if (hashSet.size() > 0) {
			Iterator<String> it = hashSet.iterator();
			while (it.hasNext()) {
				if (emailId.equalsIgnoreCase((String) it.next()))
					return true;
			}
		}
		return false;
	}

	class SMTPAuthenticator extends Authenticator {
		protected PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication("test@gmail.com", "test");
		}
	}

}
